const NodeMediaServer = require('node-media-server');
const ffmpeg = require('fluent-ffmpeg');
const path = require('path');
const fs = require('fs');
const { execSync } = require('child_process');
const config = require('../config/server.config.js');

class StreamService {
  constructor() {
    // 自动检测并配置FFmpeg路径
    this.setupFFmpegPath();
    
    this.nms = new NodeMediaServer(config);
    this.setupEventHandlers();
    this.pullStreams = new Map(); // 存储拉流任务
    
    // 内部跟踪流状态
    this.activeStreams = {
      publishers: {},
      players: {}
    };
  }

  setupFFmpegPath() {
    try {
      let ffmpegPath;
      const isWindows = process.platform === 'win32';
      const ffmpegExe = isWindows ? 'ffmpeg.exe' : 'ffmpeg';
      
      // 检测FFmpeg路径的优先级顺序
      const searchPaths = [
        // 1. 优先检查项目根目录（开发环境）
        path.resolve(__dirname, '../../', ffmpegExe),
        
        // 2. 检查打包程序同目录（生产环境）
        path.resolve(process.execPath, '..', ffmpegExe),
        
        // 3. 检查bin目录
        path.resolve(__dirname, '../../bin/', ffmpegExe),
        
        // 4. 检查当前工作目录
        path.resolve(process.cwd(), ffmpegExe)
      ];
      
      console.log('开始搜索FFmpeg路径...');
      // 首先尝试本地路径
      for (const testPath of searchPaths) {
        console.log('检查路径:', testPath);
        if (fs.existsSync(testPath)) {
          ffmpegPath = testPath;
          console.log('✓ 找到FFmpeg:', ffmpegPath);
          break;
        } else {
          console.log('✗ 路径不存在:', testPath);
        }
      }
      
      // 如果本地没有找到，尝试系统PATH
      if (!ffmpegPath) {
        try {
          const command = isWindows ? 'where ffmpeg' : 'which ffmpeg';
          ffmpegPath = execSync(command, { encoding: 'utf8' }).trim().split('\n')[0];
          console.log('在系统PATH中找到FFmpeg:', ffmpegPath);
        } catch (error) {
          // 最后使用默认命令
          ffmpegPath = 'ffmpeg';
          console.warn('⚠️  未找到FFmpeg可执行文件，使用默认命令。请确保FFmpeg已安装或与程序放在同一目录');
        }
      }
      
      ffmpeg.setFfmpegPath(ffmpegPath);
      console.log('🎬 FFmpeg路径已配置:', ffmpegPath);
      
      // 验证FFmpeg是否可用
      this.testFFmpegPath(ffmpegPath);
      
    } catch (error) {
      console.error('❌ 配置FFmpeg路径时出错:', error.message);
      ffmpeg.setFfmpegPath('ffmpeg'); // 使用默认命令
    }
  }
  
  testFFmpegPath(ffmpegPath) {
    try {
      // 测试FFmpeg是否可执行
      const testCommand = `"${ffmpegPath}" -version`;
      const result = execSync(testCommand, { encoding: 'utf8', timeout: 5000 });
      if (result.includes('ffmpeg version')) {
        console.log('✅ FFmpeg测试成功');
        return true;
      }
    } catch (error) {
      console.error('❌ FFmpeg测试失败:', error.message);
      console.error('请检查FFmpeg文件是否存在且可执行');
    }
    return false;
  }

  setupEventHandlers() {
    this.nms.on('preConnect', (id, args) => {
      console.log('[节点事件 preConnect]', `id=${id} 参数=${JSON.stringify(args)}`);
      // Handle pre-connection logic if needed
    });

    this.nms.on('postConnect', (id, args) => {
      console.log('[节点事件 postConnect]', `id=${id} 参数=${JSON.stringify(args)}`);
    });

    this.nms.on('doneConnect', (id, args) => {
      console.log('[节点事件 doneConnect]', `id=${id} 参数=${JSON.stringify(args)}`);
    });

    this.nms.on('prePublish', (id, StreamPath, args) => {
      console.log('[节点事件 prePublish]', `id=${id} 流路径=${StreamPath} 参数=${JSON.stringify(args)}`);
      // Handle pre-publish logic (authentication, validation, etc.)
    });

    this.nms.on('postPublish', (id, StreamPath, args) => {
      console.log('[节点事件 postPublish]', `id=${id} 流路径=${StreamPath} 参数=${JSON.stringify(args)}`);
      // 记录活跃流
      const streamName = StreamPath.split('/').pop();
      this.activeStreams.publishers[streamName] = {
        id,
        streamPath: StreamPath,
        startTime: new Date(),
        args
      };
      // Handle post-publish logic (notifications, etc.)
    });

    this.nms.on('donePublish', (id, StreamPath, args) => {
      console.log('[节点事件 donePublish]', `id=${id} 流路径=${StreamPath} 参数=${JSON.stringify(args)}`);
      // 移除活跃流
      const streamName = StreamPath.split('/').pop();
      delete this.activeStreams.publishers[streamName];
    });

    this.nms.on('prePlay', (id, StreamPath, args) => {
      console.log('[节点事件 prePlay]', `id=${id} 流路径=${StreamPath} 参数=${JSON.stringify(args)}`);
      // Handle pre-play logic (authentication, validation, etc.)
    });

    this.nms.on('postPlay', (id, StreamPath, args) => {
      console.log('[节点事件 postPlay]', `id=${id} 流路径=${StreamPath} 参数=${JSON.stringify(args)}`);
      // 记录播放者
      const streamName = StreamPath.split('/').pop();
      if (!this.activeStreams.players[streamName]) {
        this.activeStreams.players[streamName] = [];
      }
      this.activeStreams.players[streamName].push({
        id,
        streamPath: StreamPath,
        startTime: new Date(),
        args
      });
    });

    this.nms.on('donePlay', (id, StreamPath, args) => {
      console.log('[节点事件 donePlay]', `id=${id} 流路径=${StreamPath} 参数=${JSON.stringify(args)}`);
      // 移除播放者
      const streamName = StreamPath.split('/').pop();
      if (this.activeStreams.players[streamName]) {
        this.activeStreams.players[streamName] = this.activeStreams.players[streamName].filter(player => player.id !== id);
        if (this.activeStreams.players[streamName].length === 0) {
          delete this.activeStreams.players[streamName];
        }
      }
    });
    
    // 调试：检查nms对象的可用方法和属性
    console.log('Node Media Server 可用方法:', Object.getOwnPropertyNames(this.nms).filter(name => typeof this.nms[name] === 'function'));
    console.log('Node Media Server 可用属性:', Object.getOwnPropertyNames(this.nms).filter(name => typeof this.nms[name] !== 'function'));
    
    // 检查是否有sessions属性
    if (this.nms.sessions) {
      console.log('Node Media Server sessions 结构:', Object.keys(this.nms.sessions));
    }
  }

  async start() {
    this.nms.run();
    console.log(`流媒体服务器已启动，RTMP端口 ${config.rtmp.port}，HTTP端口 ${config.http.port}`);
    
    // 验证FFmpeg是否正确配置
    const ffmpegValid = await this.validateFFmpeg();
    if (!ffmpegValid) {
      console.warn('警告: FFmpeg验证失败，流媒体转码功能可能不可用');
    }
  }
  
  validateFFmpeg() {
    return new Promise((resolve) => {
      ffmpeg.getAvailableCodecs((err, codecs) => {
        if (err) {
          console.error('FFmpeg配置错误:', err.message);
          console.error('请确保FFmpeg可执行文件与程序在同一目录或已添加到系统PATH');
          resolve(false);
          return;
        }
        console.log('FFmpeg配置成功，可用编解码器数量:', Object.keys(codecs).length);
        resolve(true);
      });
    });
  }

  stop() {
    // 停止所有拉流任务
    for (let [streamName, pullProcess] of this.pullStreams) {
      if (pullProcess) {
        pullProcess.kill();
        console.log(`已停止拉流任务: ${streamName}`);
      }
    }
    
    this.nms.stop();
    console.log('流媒体服务器已停止');
  }

  getStreams() {
    // 使用内部跟踪的流状态
    return this.activeStreams;
  }

  getConnections() {
    // 返回内部跟踪的流状态
    return this.activeStreams;
  }
  
  // 添加拉流任务（支持RTMP和RTSP源）
  addPullStream(streamName, sourceUrl) {
    try {
      // 检查源URL类型
      const isRtsp = sourceUrl.toLowerCase().startsWith('rtsp://');
      const isRtmp = sourceUrl.toLowerCase().startsWith('rtmp://');
      
      if (!isRtsp && !isRtmp) {
        throw new Error('不支持的流媒体协议，仅支持RTMP和RTSP');
      }
      
      // 构建目标RTMP地址
      const targetRtmpUrl = `rtmp://127.0.0.1:${config.rtmp.port}/live/${streamName}`;
      
      // 配置FFmpeg选项
      let ffmpegCommand = ffmpeg(sourceUrl);
      
      if (isRtsp) {
        // RTSP特定选项 - 优化延迟
        ffmpegCommand = ffmpegCommand
          .inputOptions([
            '-rtsp_transport tcp',     // 使用TCP传输以获得更稳定的连接
            '-timeout 5000000',        // 设置5秒超时（微秒）
            '-fflags nobuffer',        // 禁用输入缓冲区
            '-flags low_delay',        // 低延迟标志
            '-probesize 32768',        // 减少探测大小以加快启动
            '-analyzeduration 1000000' // 减少分析时间（1秒）
          ]);
      } else if (isRtmp) {
        // RTMP特定选项 - 优化延迟
        ffmpegCommand = ffmpegCommand
          .inputOptions([
            '-fflags nobuffer',        // 禁用输入缓冲区
            '-flags low_delay',        // 低延迟标志
            '-probesize 32768',        // 减少探测大小以加快启动
            '-analyzeduration 1000000' // 减少分析时间（1秒）
          ]);
      }
      
      // 通用输出选项 - 优化防闪烁
      ffmpegCommand = ffmpegCommand
        .outputOptions([
          '-c:v libx264',            // 视频编码器
          '-preset fast',            // 使用fast预设平衡质量和性能
          '-tune zerolatency',       // 零延迟调优
          '-profile:v baseline',     // 基准profile以减少解码复杂性
          '-c:a aac',                // 音频编码器
          '-b:a 128k',               // 音频比特率
          '-ar 44100',               // 标准音频采样率
          '-f flv',                  // 输出格式
          '-g 50',                   // 增大GOP减少关键帧频率
          '-keyint_min 25',          // 最小关键帧间隔
          '-sc_threshold 0',         // 禁用场景检测，保持固定GOP
          '-b:v 2000k',              // 适中的视频比特率
          '-maxrate 2500k',          // 最大比特率
          '-bufsize 5000k',          // 增大缓冲区提高稳定性
          '-crf 23',                 // 适中的CRF值平衡质量和稳定性
          '-pix_fmt yuv420p',        // 设置像素格式以确保兼容性
          '-movflags +faststart',    // 优化流媒体播放
          '-vsync cfr',              // 使用恒定帧率同步消除闪烁
          '-threads 4',              // 限制线程数避免过度并发
          '-bf 0',                   // 禁用B帧减少延迟和闪烁
          '-fflags +genpts+igndts',  // 生成PTS并忽略DTS问题
          '-r 25',                   // 固定帧率为25fps
          '-force_key_frames expr:gte(t,n_forced*2)', // 每2秒强制一个关键帧
          '-avoid_negative_ts make_zero',   // 避免负时间戳
          '-max_muxing_queue_size 1024',   // 增加复用队列大小
          '-rtmp_live 1',            // 启用RTMP实时模式
          '-x264-params keyint=50:min-keyint=25:scenecut=0:bframes=0' // 直接设置x264参数
        ])
        .output(targetRtmpUrl)
        .on('start', (commandLine) => {
          console.log(`拉流任务启动: ${commandLine}`);
        })
        .on('error', (err) => {
          console.error(`拉流任务错误 (${streamName}):`, err.message);
          this.pullStreams.delete(streamName);
        })
        .on('end', () => {
          console.log(`拉流任务结束: ${streamName}`);
          this.pullStreams.delete(streamName);
        })
        .run();
      
      // 存储拉流任务
      this.pullStreams.set(streamName, ffmpegCommand);
      
      console.log(`已添加拉流任务: ${streamName} <- ${sourceUrl}`);
      return { success: true, streamName, sourceType: isRtsp ? 'RTSP' : 'RTMP' };
    } catch (error) {
      console.error('添加拉流任务时出错:', error);
      return { success: false, error: error.message };
    }
  }
  
  // 移除拉流任务
  removePullStream(streamName) {
    try {
      const pullProcess = this.pullStreams.get(streamName);
      if (pullProcess) {
        pullProcess.kill();
        this.pullStreams.delete(streamName);
        console.log(`已移除拉流任务: ${streamName}`);
        return { success: true };
      } else {
        console.log(`未找到拉流任务: ${streamName}`);
        return { success: false, message: '未找到拉流任务' };
      }
    } catch (error) {
      console.error('移除拉流任务时出错:', error);
      return { success: false, error: error.message };
    }
  }
  
  // 获取流播放地址
  getStreamPlayUrl(streamName) {
    // 返回HTTP-FLV播放地址
    return `http://localhost:${config.http.port}/live/${streamName}.flv`;
  }
  
  // 获取RTMP播放地址
  getRtmpPlayUrl(streamName) {
    // 返回RTMP播放地址
    return `rtmp://localhost:${config.rtmp.port}/live/${streamName}`;
  }
}

module.exports = StreamService;